package com.ckjava.test.service.base;

import com.ckjava.test.domain.base.BaseJpaEntity;
import com.ckjava.xutils.Constants;
import com.ckjava.xutils.http.Page;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.*;
import java.util.*;

@Transactional(readOnly = true)
public abstract class BaseJpaCrudService<E extends BaseJpaEntity> implements Constants {

    @PersistenceContext
    private EntityManager entityManager;

    /**
     * 获取子类的 Class 类型
     * @return
     */
    public abstract Class<E> getClassType();

    /**
     * 提供具体的字段以供搜索， 也就是具体实体中的字段名称
     * @return
     */
    public abstract String[] getSearchFields();

    /**
     * 根据 id 查询一个对象
     * @param id
     * @return
     */
    public E get(Long id) {
        return entityManager.find(getClassType(), id);
    }

    /**
     * 根据关键字搜索对象
     * @param keyword
     * @return
     */
    public List<E> search(String keyword) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<E> q = cb.createQuery(getClassType());
        Root<E> c = q.from(getClassType());
        q.select(c);

        String[] orFields = getSearchFields();
        Predicate[] orPredicate = new Predicate[orFields.length];
        for (int i = 0, len = orFields.length; i < len; i++) {
            orPredicate[i] = cb.like(c.get(orFields[i]), "%" + keyword + "%");
        }

        // 加上默认条件 和 所有 or 的条件
        q.where(cb.and(cb.equal(c.get("delFlag"), BaseJpaEntity.DEL_NO)),
                cb.or(orPredicate));
        return entityManager.createQuery(q).getResultList();
    }

    /**
     * 获取所有
     * @return
     */
    public List<E> findAll() {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<E> q = cb.createQuery(getClassType());
        Root<E> c = q.from(getClassType());
        q.select(c);
        // 加上默认条件
        q.where(cb.equal(c.get("delFlag"), BaseJpaEntity.DEL_NO));
        return entityManager.createQuery(q).getResultList();
    }

    /**
     * 分页获取数据
     * @param e
     * @return
     */
    public Page<E> getPage(E e) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<E> q = cb.createQuery(getClassType());
        Root<E> c = q.from(getClassType());
        q.select(c);

        List<Predicate> whereList = new ArrayList<>();
        // 默认条件
        whereList.add(cb.equal(c.get("delFlag"), e.DEL_NO));

        // 设置查询条件
        Map<String, String> conditionMap = e.getConditionMap();
        if (conditionMap != null && !conditionMap.isEmpty()) {
            for (Iterator<Map.Entry<String, String>> it = conditionMap.entrySet().iterator(); it.hasNext();) {
                Map.Entry<String, String> entry = it.next();
                // key name, value like,张三
                // key age, value =,10
                // op: like, =

                String key = entry.getKey();
                String value = entry.getValue();
                String op = value.split(SPLITER.COMMA)[0];

                if (op.equals("like")) {
                    whereList.add(cb.like(c.get(key), "%"+value+"%"));
                } else if (op.equals("=")) {
                    whereList.add(cb.equal(c.get(key), value));
                } else {
                    whereList.add(cb.like(c.get(key), "%"+value+"%"));
                }
            }
        }

        q.where(whereList.toArray(new Predicate[whereList.size()]));

        // 设置排序字段
        Order order;
        if (e.getDesc()) {
            order = cb.desc(c.get(e.getOrderBy()));
        } else {
            order = cb.asc(c.get(e.getOrderBy()));
        }
        q.orderBy(order);

        // 获取当前页数据
        TypedQuery<E> pageQuery = entityManager.createQuery(q)
                .setFirstResult(e.getStart())
                .setMaxResults(e.getPageSize());

        // 当前条件的记录数
        TypedQuery<E> countQuery = entityManager.createQuery(q);

        return new Page<>(e.getStart(), e.getPageSize(), countQuery.getResultList().size(), pageQuery.getResultList());
    }

    @Transactional
    public Long saveOrUpdate(E e) {
        if (e.getId() == null) {
            return save(e);
        } else {
            return update(e).getId();
        }
    }

    @Transactional
    public Long save(E e) {
        e.setDelFlag(E.DEL_NO);
        e.setCreateDate(new Date());
        entityManager.persist(e);
        return e.getId();
    }

    @Transactional
    public E update(E e) {
        e.setUpdateDate(new Date());
        return entityManager.merge(e);
    }

    @Transactional
    public void delete(E e) {
        e.setDelFlag(E.DEL_YES);
        update(e);
    }

    @Transactional
    public void delete(Long id) {
        E e = get(id);
        delete(e);
    }

}
